# coding=utf-8
import logging
from django.db import transaction
from django.db.models import Q, F, Sum
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
from rest_framework import viewsets, status
from MSB_ERP.utils.base_views import MultipleDestoryMixin
from rest_framework.decorators import action
from rest_framework.response import Response
from erp_system.models import UserModel
from basic_info.models import SupplierModel
from goods_info.models import GoodsInventoryModel
from warehouse_info.serializer.in_storage_serializer import InStorageSerializer, InStorageGetSerializer
from warehouse_info.models import PurchaseStorageModel

logger = logging.getLogger('erp')

class InStorageView(viewsets.ModelViewSet,MultipleDestoryMixin):
    '''
        create:
        仓库（采购）--新增，注意：其中images_list="1,2,3,4";里面是附件的ID

        仓库（采购）新增，status：201（成功），return：新增仓库（采购）信息

        destory:
        仓库（采购）--删除

        仓库（采购）删除，status：204（成功），return：None

        multiple_delete:
        仓库（采购）--批量删除，必传参数：ids=[1,2,3,4...]

        仓库（采购）批量删除，status：204（成功），return：None

        update:
        仓库（采购）--修改，注意：其中images_list="1,2,3,4";里面是附件的ID

        仓库（采购）修改，status：200（成功），return：修改后的仓库（采购）信息

        partial_update:
        仓库（采购）--局部修改，可以传参任意属性的值，服务器会修改指定的属性值

        仓库（采购）局部修改，status：200（成功），return：修改后的仓库（采购）信息

        list:
        仓库（采购）--该接口可以弃用

        仓库（采购）列表信息，status：200（成功），return：仓库（采购）信息列表

        retrieve：
        查询某一个仓库（采购）

        查询指定ID的仓库（采购），status：200（成功），return：用户仓库（采购）
    '''

    queryset = PurchaseStorageModel.objects.all()
    serializer_class = InStorageSerializer

    def get_serializer_class(self):
        if self.action == 'retrieve':
            return InStorageGetSerializer
        return InStorageSerializer

    def get_queryset(self):
        if self.action == 'find':  # 过滤查询
            # 获取请求参数(在json中)：
            number_code = self.request.data.get('number_code', None)
            keyword = self.request.data.get('keyword', None)
            start_date = self.request.data.get('start_date', None)
            end_date = self.request.data.get('start_date', None)
            supplier = self.request.data.get('supplier', 0)
            operator_user = self.request.data.get('operator_user', 0)
            status = self.request.data.get('status', None)

            warehuose = self.request.data.get('warehuose', None)
            account = self.request.data.get('account', None)
            purchase_number_code = self.request.data.get('purchase_number_code', None)

            query = Q()
            if keyword:
                child_query = Q()
                child_query.add(Q(item_list__name__contains=keyword), 'OR')
                child_query.add(Q(item_list__specification=keyword), 'OR')
                query.add(child_query, 'AND')
            if start_date:
                query.add(Q(invoices_date__gt=start_date), 'AND')
            if end_date:
                query.add(Q(invoices_date__lt=end_date), 'AND')

            if supplier:
                query.add(Q(supplier__id=supplier), 'AND')
            if number_code:
                query.add(Q(number_code__contains=number_code), 'AND')
            if operator_user:
                query.add(Q(operator_user__id=operator_user), 'AND')
            if status:
                query.add(Q(status=status), 'AND')

            if warehuose:
                query.add(Q(warehuose__contains=warehuose), 'AND')
            if account:
                query.add(Q(account__contains=account), 'AND')
            if purchase_number_code:
                query.add(Q(purchase_number_code=purchase_number_code), 'AND')

            return PurchaseStorageModel.objects.filter(query).distinct().all()
        else:
            return PurchaseStorageModel.objects.all()

    params = openapi.Schema(type=openapi.TYPE_OBJECT, properties={
        'keyword': openapi.Schema(type=openapi.TYPE_STRING, description="名称的关键字或者型号"),
        'start_date': openapi.Schema(type=openapi.TYPE_STRING, description="起始日期2020-10-01"),
        'number_code': openapi.Schema(type=openapi.TYPE_STRING, description="编号(序列号)"),
        'end_date': openapi.Schema(type=openapi.TYPE_STRING, description="结束日期2020-10-01"),
        'status': openapi.Schema(type=openapi.TYPE_STRING, description="状态0或者1,2,3.."),
        'supplier': openapi.Schema(type=openapi.TYPE_INTEGER, description="供应商的ID"),
        'operator_user': openapi.Schema(type=openapi.TYPE_INTEGER, description="操作用户的ID"),
        'waarehuose': openapi.Schema(type=openapi.TYPE_INTEGER, description="仓库ID"),
        'account': openapi.Schema(type=openapi.TYPE_INTEGER, description="结算账户的ID"),
        'purchase_number_code': openapi.Schema(type=openapi.TYPE_INTEGER, description="采购单号"),
    })
    # 分页参数必须是query_param(看源码)
    page_param = openapi.Parameter(name='page', in_=openapi.IN_QUERY, description="页号", type=openapi.TYPE_INTEGER)
    size_param = openapi.Parameter(name='size', in_=openapi.IN_QUERY, description="每页显示数量",
                                   type=openapi.TYPE_INTEGER)

    @swagger_auto_schema(method='POST', request_body=params, manual_parameters=[page_param, size_param],
                         operation_description="采购订单的搜索过滤")
    @action(methods=['POST'], detail=False)
    def find(self, request, *args, **kwargs):
        return super(InStorageView, self).list(request=request, *args, **kwargs)

    body_json = openapi.Schema(type=openapi.TYPE_OBJECT, required=['ids'], properties={
        'ids': openapi.Schema(type=openapi.TYPE_ARRAY, items=openapi.Schema(type=openapi.TYPE_INTEGER),
                              description='选择那些需要是审批（主键）的列表'), # id可以传多个
        'user_id': openapi.Schema(type=openapi.TYPE_INTEGER, description='审核用户的ID')    })

    # 这个是特别的接口文档，methods表示请求的方法，request_body表示指定传参
    @swagger_auto_schema(method='put', request_body=body_json, operation_description='审核反审核')  # 装饰器一定要写在action的上面
    @action(methods=['put'], detail=False)
    @transaction.atomic # 数据库事务（第二种方法，他会适用整一个视图函数）
    def multiple_audit1(self, request, *args, **kwargs):
        audit_ids = request.data.get('ids')
        user_id = request.data.get('user_id') # 用户ID
        is_audit = '1' # 只能做审核

        # 如果没有数据
        if not audit_ids:
            return Response(
                data={'detail': '参数错误，ids是必传参数'},
                status=status.HTTP_400_BAD_REQUEST
            )
        # 传过来的数据必须是列表
        if not isinstance(audit_ids, list):
            return Response(
                data={'detail': '参数错误，ids是必须是一个列表'},
                status=status.HTTP_400_BAD_REQUEST
            )
        # 其实这里是调用了子类的query
        # 这里是包含所有的批量审批的采购单
        in_list = self.get_queryset().all().filter(id__in=audit_ids)
        # 审批用户
        check_user = UserModel.objects.get(id=int(user_id))

        for in_storage in in_list:
            # 审批的条件判断:1.入库单的状态必须是0
            #              2.是否关联了采购单
            if in_storage.status != '0': # 0 以后的状态是不是审批的
                return Response(
                data={'detail': '不能审批，因为订单已经生效'},
                status=status.HTTP_400_BAD_REQUEST
                )
            if in_storage.purchase: # 如果数据存在就是关联了采购单
                if in_storage.purchase.status != '1' and in_storage.purchase.status != '2' and in_storage.purchase.status != '5':
                    # 不能进行审核操作
                    return Response(
                        data={'detail': '不能审批，因为关联的采购订单未生效'},
                        status=status.HTTP_400_BAD_REQUEST
                    )
            # 处理业务逻辑（如果供应商存在并且还有欠款）
            if in_storage.supplier and in_storage.this_debt > 0: # 修改供应商的末期应付 += 本次欠款
                SupplierModel.objects.filter(id=in_storage.supplier.id)\
                    .update(current_pay=F('current_pay') + in_storage.this_debt) # F获取原有的某一个字段的值 + 本次欠款，然后重新赋值给current_pay这个字段

            if in_storage.purchase: # 修改关联的采购订单，状态为：部分入库和全部入库
                # 查询该采购单，已经入库的数量（in_count已经入库的数量）
                in_count = PurchaseStorageModel.objects.filter(purchase_id=in_storage.purchase.id)\
                    .exclude(status=0).aggregate(sum=Sum('number_count')) # exclude就是排除的意思（这里的意思是排除状态！=0）
                if not in_count.get('sum',0): # sum是上面in_count中的入库数量的总和
                    in_count = 0

                if (in_count + in_storage.number_count) == in_storage.purchase.number_count:
                    in_storage.purchase.status = '3' # 修改为全部入库
                else:
                    in_storage.purchase.status = '2' # 修改为部分入库
                in_storage.purchase.save()

            # 相关货品的库存，需要增加：原来的库存 += 当前入库的数量
            for item in in_storage.item_list.all():
                GoodsInventoryModel.objects.filter(goods_id=item.goods_id,warehouse_id=item.warehouse_id)\
                    .update(cur_inventory=F('cur_inventory') + item.purchase_count)

        # 审核（修改）
        self.get_queryset().all().filter(id__in=audit_ids).update(status=is_audit,check_user_id=check_user.id,check_user_name=check_user.real_name)
        return Response(status=status.HTTP_200_OK)












